package org.sxp.modules.dataworks.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xxl.job.admin.controller.JobInfoController;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.sxp.common.dto.DatabaseDTO;
import org.sxp.common.dto.TableNamesDTO;
import org.sxp.common.exception.BusinessException;
import org.sxp.common.utils.*;
import org.sxp.modules.datasource.dto.PubTableDTO;
import org.sxp.modules.datasource.entity.DatabaseDO;
import org.sxp.modules.datasource.service.DatabaseService;
import org.sxp.modules.dataworks.dto.DevelopResultDTO;
import org.sxp.modules.dataworks.entity.DevelopDO;
import org.sxp.modules.dataworks.service.DevelopService;
import org.sxp.modules.dataworks.dto.DevelopDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.sxp.common.annotation.SysLog;
import org.sxp.common.web.WrapperResponse;
import org.sxp.modules.dataworks.utils.XxlJobLogCaptureUtil;
import org.sxp.modules.sys.controller.AbstractController;
import org.apache.shiro.authz.annotation.RequiresPermissions;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 数据开发
 * @author 沈兴平
 * @date 2022/02/09
 */
@Controller
@RequestMapping(value = "/dataworks/develop")
@Api(description="Develop", tags = "数据开发")
@SysLog(modules = "dataworks", value = "数据开发")
public class DevelopController extends AbstractController{

    public static final String SELECT = "select";
    @Autowired
    private DevelopService developService;

    @Autowired
    private DatabaseService databaseService;

    @Resource
    public XxlJobLogDao xxlJobLogDao;
    @Resource
    private XxlJobInfoDao xxlJobInfoDao;
    @Resource
    private JobInfoController jobInfoController;
    @Resource
    private XxlJobService xxlJobService;

    @RequestMapping("/index")
    public String module(HttpServletRequest request, Model model){
        jobInfoController.index(request, model, -1);
        return "modules/dataworks/develop.html";
    }

    /**
     * 列表
     */
    @ApiImplicitParams({
            @ApiImplicitParam(name="pageNum", value = "当前页码", dataType="int", paramType = "header"),
            @ApiImplicitParam(name="pageSize",value="每页条目",dataType="int", paramType = "header"),
            @ApiImplicitParam(name="orderField",value="排序字段",dataType="string", paramType = "header"),
            @ApiImplicitParam(name="orderType",value="排序类型",dataType="string", paramType = "header", example = "asc或者desc")
    })
    @RequestMapping(value = "/list",method = {RequestMethod.POST})
    @ApiOperation(value = "查询列表")
    @RequiresPermissions("dataworks:develop:list")
    @ResponseBody
    public WrapperResponse<List<DevelopDTO>> list(DevelopDTO params) throws Exception{
        //请求头获取分页参数
        PageInfo pageInfo = buildPageInfo();
        IPage<DevelopDO> page = developService.page(
                new Query<DevelopDO>().getPage(pageInfo),
                new LambdaQueryWrapper<DevelopDO>()
                        .eq(DevelopDO::getSpaceId, params.getSpaceId())
                        .like(StrUtil.isNotBlank(params.getName()), DevelopDO::getName, params.getName())
        );

        for(DevelopDO developDO : page.getRecords()){
            if(developDO.getJobinfoId() != null){
                XxlJobInfo jobInfo = xxlJobInfoDao.loadById(developDO.getJobinfoId());
                if(jobInfo != null){
                    developDO.setJobinfoName(jobInfo.getName());
                }
            }
            if(StrUtil.isNotBlank(developDO.getDevelopDb())){
                DatabaseDO databaseDO = databaseService.getById(developDO.getDevelopDb());
                if(databaseDO != null){
                    developDO.setDevelopDbName(databaseDO.getName());
                }
            }
        }
        return (WrapperResponse)WrapperResponse.success(new PageResult(page));
    }


    /**
     * 执行SQL
     */
    @RequestMapping(value = "/execute", method = {RequestMethod.POST})
    @ApiOperation(value = "执行SQL")
    @ResponseBody
    public WrapperResponse<DevelopResultDTO> execute(String sql,String dbId,
                                               @RequestParam(value = "page")
                                               int pageNum, int rows) throws Exception{
        DevelopResultDTO resultDTO = new DevelopResultDTO();
        long beginTime = System.currentTimeMillis();
        try {
            DatabaseDO pubDb = databaseService.getById(dbId);
            if (pubDb == null) {
                throw new BusinessException("数据源不存在!!!");
            }
            DatabaseDTO databaseDTO = XPBeanUtils.copyBean(pubDb, DatabaseDTO.class);
            if (sql.toLowerCase().startsWith(SELECT)) {
                Page page = new Page(pageNum - 1, rows);
                List obj = DbUtil.excutePage(databaseDTO, sql, page);
                DevelopResultDTO.Zxjg zxjg = resultDTO.new Zxjg();
                zxjg.setRows(obj);
                zxjg.setCount(obj.size());
                resultDTO.setZxjg(zxjg);
                resultDTO.setCode(0);
                resultDTO.setSuccess(true);

                List<Map> colMap = DbUtil.getFieldNamesBySql(databaseDTO, sql);
                List<DevelopResultDTO.Column> columnList = new ArrayList<>();
                for(Map temp : colMap){
                    DevelopResultDTO.Column column = resultDTO.new Column();
                    column.setTitle(temp.get("name").toString());
                    column.setField(temp.get("name").toString());
                    columnList.add(column);
                }
                resultDTO.setColumns(columnList);
                resultDTO.setMsg("查询成功!!!");
            }else{
                int index = DbUtil.excuteCUD(databaseDTO, sql);
                resultDTO.setMsg("受影响行数：" + index);
            }
        }catch (Exception ex){
            resultDTO.setMsg("异常信息：" + ex.getMessage());
        }finally {
            long endTime = System.currentTimeMillis();
            resultDTO.setMs(endTime - beginTime);
        }
        return WrapperResponse.success(resultDTO);
    }

    /**
     * 绑定调度
     */
    @RequestMapping(value = "/bindJob", method = {RequestMethod.POST})
    @ApiOperation(value = "绑定调度")
    @ResponseBody
    public WrapperResponse bindJob(@RequestBody XxlJobInfo jobInfo, @RequestParam String id) throws Exception{
        DevelopDO entity = developService.getById(id);
        ReturnT<String> r = null;
        if(jobInfo.getId() > 0){
            ReturnT<XxlJobInfo> oldJobInfo = jobInfoController.loadById(jobInfo.getId());

            r = jobInfoController.update(jobInfo);
            r.setContent(String.valueOf(jobInfo.getId()));
            if(r.getCode() == ReturnT.SUCCESS_CODE && oldJobInfo.getContent().getTriggerStatus() != jobInfo.getTriggerStatus()){
                // 绑定调度的运行状态不等于老数据
                if(jobInfo.getTriggerStatus() == 1){
                    jobInfoController.start(jobInfo.getId());
                }else{
                    jobInfoController.pause(jobInfo.getId());
                }
            }
        }else{
            r = jobInfoController.add(jobInfo);
            if(r.getCode() == ReturnT.SUCCESS_CODE){
                entity.setJobinfoId(Integer.parseInt(r.getContent()));
                developService.updateById(entity);

                // 绑定调度的运行状态不等于老数据
                if(jobInfo.getTriggerStatus() == 1){
                    jobInfoController.start(jobInfo.getId());
                }
            }
        }
        return r.getCode() == ReturnT.SUCCESS_CODE ? WrapperResponse.success(r.getContent()) : WrapperResponse.fail(r.getMsg(), r.getContent());
    }

    /**
     * 执行调度
     */
    @RequestMapping(value = "/executeJob", method = {RequestMethod.POST})
    @ApiOperation(value = "执行调度")
    @ResponseBody
    public WrapperResponse excuteJob(@RequestBody DevelopDTO develop) throws Exception{
        List<XxlJobLog> activeLog = xxlJobLogDao.findJobActiveLog(develop.getJobinfoId());
        if(activeLog != null && activeLog.size() > 0){
            return WrapperResponse.fail("工作绑定的调度正在执行任务，请结束后再执行!!!", null);
        }
        // 执行前先保存
        WrapperResponse response = update(develop);

        if(response.getCode() == WrapperResponse.SUCCESS){
            ReturnT<XxlJobInfo> returnT = jobInfoController.loadById(develop.getJobinfoId());
            if(returnT.getCode() == ReturnT.SUCCESS_CODE && returnT.getContent() != null){
                XxlJobInfo jobInfo = returnT.getContent();
                try {
                    String snapshotId = IdUtil.simpleUUID();
                    XxlJobLogCaptureUtil.jobLogContext.set(snapshotId);
                    ReturnT<String> triggerReturnT = jobInfoController.triggerJob(develop.getJobinfoId(), jobInfo.getExecutorParam(), null);
                    if (triggerReturnT.getCode() == ReturnT.SUCCESS_CODE) {
                        int index = 5;
                        while(index > 0){
                            XxlJobLog jobLog = xxlJobLogDao.loadBySnapshotId(snapshotId);
                            if(jobLog != null){
                                return WrapperResponse.success(jobLog.getId());
                            }
                            Thread.sleep(1000);
                            index--;
                        }
                    } else {
                        throw new BusinessException("调度执行失败:" + triggerReturnT.getMsg());
                    }
                }catch (Exception e){
                    throw e;
                }finally {
                    XxlJobLogCaptureUtil.jobLogContext.remove();
                }
            }else{
                return WrapperResponse.fail("调度任务不存在，可能被移除，请重新配置。", null);
            }
        }else{
            return WrapperResponse.fail("执行前保存失败!!!");
        }
        return WrapperResponse.success(null);
    }

    /**
     * 信息
     */
    @RequestMapping(value = "/info/{id}", method = {RequestMethod.GET})
    @ApiOperation(value = "查询")
    @RequiresPermissions("dataworks:develop:info")
    @ResponseBody
    public WrapperResponse<DevelopDTO> info(@PathVariable String id) throws Exception{
        DevelopDO develop = developService.getById(id);

        return (WrapperResponse)WrapperResponse.success(develop);
    }

    /**
     * 保存
     */
    @RequestMapping(value = "/save",method = {RequestMethod.POST})
    @ApiOperation(value = "保存")
    @SysLog("保存")
    @RequiresPermissions("dataworks:develop:save")
    @ResponseBody
    public WrapperResponse<DevelopDTO> save(@RequestBody DevelopDTO develop) throws Exception{
        boolean boo = developService.save(DevelopDO.copyBean(develop));
//        if(boo && develop.getJobinfoId() != null){
//            updateJobParam(develop);
//        }
        return (WrapperResponse)WrapperResponse.success(null);
    }

    /**
     * 修改
     */
    @RequestMapping(value = "/update",method = {RequestMethod.POST})
    @ApiOperation(value = "修改")
    @SysLog("修改")
    @RequiresPermissions("dataworks:develop:update")
    @ResponseBody
    public WrapperResponse<DevelopDTO> update(@RequestBody DevelopDTO develop) throws Exception{
        develop.setSqlScript(StrUtil.isNotBlank(develop.getSqlScript()) ? develop.getSqlScript().trim() : null);
        boolean boo = developService.updateById(DevelopDO.copyBean(develop));
//        if(boo && develop.getJobinfoId() != null){
//            updateJobParam(develop);
//        }
        return (WrapperResponse)WrapperResponse.success(null);
    }

    /**
     * 批量删除
     */
    @RequestMapping(value = "/deleteBatch",method = {RequestMethod.POST})
    @ApiOperation(value = "批量删除")
    @SysLog("批量删除")
    @RequiresPermissions("dataworks:develop:deleteBatch")
    @ResponseBody
    public WrapperResponse deleteBatch(@RequestBody String[] ids) throws Exception{
        for(String id : ids){
            DevelopDO developDO = developService.getById(id);
            boolean boo = developService.removeById(id);
            if(boo && developDO.getJobinfoId() != null){
                xxlJobService.remove(developDO.getJobinfoId());
            }
        }
        return WrapperResponse.success(null);
    }

    /**
     * 信息
     */
    @RequestMapping(value = "/tables.json", method = {RequestMethod.GET})
    @ApiOperation(value = "查询")
    @ResponseBody
    public WrapperResponse tables(String dbId) throws Exception{
        DatabaseDO pubDb = databaseService.getById(dbId);
        if (pubDb == null) {
            throw new BusinessException("数据源不存在!!!");
        }

        Map<String, List> tableWords = new HashMap<>();
        List<TableNamesDTO> tables = DbUtil.getTableNames(XPBeanUtils.copyBean(pubDb, DatabaseDTO.class));

        List<PubTableDTO> pubTableDto = new ArrayList<>();
        PubTableDTO tableDTO = new PubTableDTO();
        tableDTO.setId(pubDb.getId());
        tableDTO.setText(pubDb.getDbName());

        List<PubTableDTO.TableChildren> tableChildren = new ArrayList<>();
        for(TableNamesDTO item : tables){
            PubTableDTO.TableChildren table = tableDTO.new TableChildren();
            table.setId(item.getTableName());
            table.setText(item.getTableName());

            tableWords.put(item.getTableName(), new ArrayList());
            List<PubTableDTO.ColumnChildren> columnChildren = new ArrayList<>();
            List<Map> colMap = DbUtil.getFieldNamesByTable(XPBeanUtils.copyBean(pubDb, DatabaseDTO.class), item.getTableName());
            for(Map<String, String> temp : colMap){
                PubTableDTO.ColumnChildren col = tableDTO.new ColumnChildren();
                col.setText(temp.get("columnName"));
                columnChildren.add(col);
                tableWords.get(item.getTableName()).add(col.getText());
            }
            table.setChildren(columnChildren);
            tableChildren.add(table);
        }


        List<PubTableDTO.Children> childrenList = new ArrayList<>();
        PubTableDTO.Children children = tableDTO.new Children();
        children.setChildren(tableChildren);
        childrenList.add(children);
        tableDTO.setChildren(childrenList);
        pubTableDto.add(tableDTO);

        Map<String, Object> data = new HashMap<>();
        data.put("pubTable", pubTableDto);
        data.put("tableWords", tableWords);
        return WrapperResponse.success(data);
    }
}
